/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package geraphp;

import br.gov.ce.sejus.util.arquivo.Arquivo;
import java.io.File;
import java.util.ArrayList;

/**
 *
 * @author alyson
 */
public class PersistenceFactory {

    private ArrayList listaAtributos = new ArrayList();
    private String nomeTabela = new String();
    private String codigoEntidade;
    private String codigoDAO;
    private String host, porta, login, senha, caminho, nomeProjeto, caminhoBean, caminhoDAO, db;
    private String msgErro = "";
    private String campoPk = "";

    public PersistenceFactory(ArrayList listaAtributos,
            String db, String host, String porta, String login, String senha,
            String caminho,
            String nomeProjeto,
            String caminhoBean,
            String caminhoDAO) {
        this.listaAtributos = listaAtributos;
        this.host = host;
        this.porta = porta;
        this.login = login;
        this.senha = senha;
        this.caminho = caminho;
        this.nomeProjeto = nomeProjeto;
        this.caminhoBean = caminhoBean;
        this.caminhoDAO = caminhoDAO;
        this.db = db;
    }

    public boolean gerarCodigo(String nomeTabela) {

        boolean retorno = false;
        try {

            if (!validaPk()) {
                throw new Exception("Tabela " + nomeTabela + " não possui pk.");
            }

            this.nomeTabela = nomeTabela;

            codigoEntidade = gerarCodigoEntidade();

            String nomeTabelaObj = primaMaiuscula(nomeTabela);

            String caminhoCompleto = caminho + nomeProjeto + File.separator;
            new Arquivo().criarArquivo(caminhoCompleto + caminhoBean + File.separator, nomeTabelaObj + "Bean.php", codigoEntidade);

            codigoDAO = gerarDaoCodigo();
            new Arquivo().criarArquivo(caminhoCompleto + caminhoDAO + File.separator, nomeTabelaObj + "Controller.php", codigoDAO);

            if (!new File(caminhoDAO + File.separator + "Conexao.php").exists()) {
                new Arquivo().criarArquivo(caminhoCompleto + caminhoDAO + File.separator, "Conexao.php", gerarSingletonConexao());
            }
            retorno = true;
        } catch (Exception ex) {
            msgErro = ex.getMessage();
            retorno = false;
        }
        return retorno;
    }

    public boolean validaPk() {

        boolean possuiPk = false;

        for (int i = 0; i < listaAtributos.size(); i++) {
            ArrayList listaTmp = (ArrayList) listaAtributos.get(i);

            if (listaTmp.get(0) == "PK") {
                possuiPk = true;
                break;
            }
        }

        return possuiPk;
    }

    private String gerarCodigoEntidade() {

        StringBuilder sb = new StringBuilder();
        StringBuilder sbPrimeiro = new StringBuilder();
        StringBuilder sbGetsSets = new StringBuilder();

        /**
         * Iniciando cabeçalho
         */
        sb.append("<?php");
        sb.append("\n\nclass " + primaMaiuscula(nomeTabela) + "{\n\n");

        for (int i = 0; i < listaAtributos.size(); i++) {
            ArrayList listaTmp = (ArrayList) listaAtributos.get(i);


            String nomeCampo = listaTmp.get(1).toString();
            String campoTipo = listaTmp.get(2).toString();


            sbPrimeiro.append(String.format(""
                    + "    private $%1s;"
                    + "\n", nomeCampo));

            String prop = primaMaiuscula(nomeCampo);

            sbGetsSets.append(String.format("\n\n"
                    + "    public function get%s(){\n"
                    + "        return $this->%s;\n"
                    + "    }", prop, nomeCampo));

            //Se for diferente de PK então o método set deve ser criado
            if (listaTmp.get(0) != "PK") {
                sbGetsSets.append(String.format("\n\n"
                        + "    public function set%s($%s){\n"
                        + "        $this->%s = $%s;\n"
                        + "    }", prop, nomeCampo, nomeCampo, nomeCampo));
            }

        }


        sb.append(sbPrimeiro.toString());
        sb.append(sbGetsSets.toString());
        sb.append("\n}\n?>");

        return sb.toString();
    }

    public String gerarDaoCodigo() {
        StringBuilder sb = new StringBuilder();

        /**
         *
         * Corpo do DAO que será gerado em php
         */
        StringBuilder insert = new StringBuilder();
        StringBuilder update = new StringBuilder();
        String primaryKey = "";

        StringBuilder insert1Meio = new StringBuilder();
        StringBuilder insert2Meio = new StringBuilder();

        StringBuilder updateValores = new StringBuilder();

        StringBuilder popularValores = new StringBuilder();
        /**
         * Iniciando cabeçalho
         */
        sb.append("<?php");
        sb.append("\n\nclass " + primaMaiuscula(nomeTabela) + "Controller{\n\n");

        for (int i = 0; i < listaAtributos.size(); i++) {
            ArrayList listaTmp = (ArrayList) listaAtributos.get(i);
            String nomeCampo = listaTmp.get(1).toString();
            String campoTipo = listaTmp.get(2).toString();
            /**
             * Garantia de que a virgula não será aplicada na última
             * posição do array.
             */
            String virgula = ",\n";

            if (i == listaAtributos.size() - 1) {
                virgula = "";
            }

            String aspas = "";

            if (campoTipo.equalsIgnoreCase("text")
                    || campoTipo.equalsIgnoreCase("varchar")
                    || campoTipo.equalsIgnoreCase("time")
                    || campoTipo.equalsIgnoreCase("date")
                    || campoTipo.equalsIgnoreCase("timestamp")) {
                aspas = "'";
            }

            //Rotina para criar o Insert
            if (listaTmp.get(0) != "PK") {
                insert1Meio.append(String.format("                      "
                        + "%s%s",
                        nomeCampo,
                        virgula));

                insert2Meio.append(String.format("                      "
                        + "%s\" . $instancia->get%s() . \"%s%s",
                        aspas,
                        primaMaiuscula(nomeCampo),
                        aspas,
                        virgula));

                popularValores.append(String.format("            "
                        + "$%s->set%s($row[\"%s\"]);\n",
                        nomeTabela,
                        primaMaiuscula(nomeCampo),
                        nomeCampo));
                updateValores.append(String.format("            "
                        + "%s=\" . ($instancia->get%s() == null ? \"null\" : \"%s\".$instancia->get%s().\"%s\") . \"%s",
                        nomeCampo,
                        primaMaiuscula(nomeCampo),
                        aspas,
                        primaMaiuscula(nomeCampo),
                        aspas,
                        virgula));
            } else {
                primaryKey = listaTmp.get(1).toString();
            }
        }

        sb.append(""
                + "    public function __construct() {\n"
                + "        if (!class_exists(\"Conexao\")) {\n"
                + "            include(\"Conexao.php\");\n"
                + "        }\n"
                + "    }\n\n");
        sb.append(delete(primaryKey));
        sb.append(insert.append(insert(insert1Meio, insert2Meio)));
        sb.append(update(primaryKey, updateValores));
        sb.append(select(primaryKey));
        sb.append(executaConsulta(popularValores));
        sb.append("\n}\n?>");

        return sb.toString();
    }

    private String insert(StringBuilder meio1, StringBuilder meio2) {
        StringBuilder sb = new StringBuilder();

        sb.append(String.format(""
                + "    public function gravar(%s $instancia){\n\n"
                + "        $resultado = false;\n"
                + "        try {\n"
                + "            $sql = \"INSERT INTO %s(\n"
                + meio1
                + "                      )VALUES(\n"
                + meio2 + ")\";\n\n"
                + "            Conexao::querySql($sql);\n"
                + "            $resultado = true;\n"
                + "        } catch (Exception $ex) {\n"
                + "            echo $ex->getMessage();\n"
                + "        }\n"
                + "        return $resultado;\n"
                + "    }\n\n", primaMaiuscula(nomeTabela),
                nomeTabela));

        return sb.toString();
    }

    private String update(String pk, StringBuilder valores) {
        StringBuilder sb = new StringBuilder();

        sb.append(String.format(""
                + "    public function atualizar(%s $instancia) {\n\n"
                + "        $resultado = false;\n\n"
                + "        try {\n"
                + "            $sql = \"UPDATE %s\n"
                + "            SET\n"
                + valores
                + "            WHERE %s = \" . $instancia->get%s();\n\n"
                + "            Conexao::querySql($sql);\n\n"
                + "            $resultado = true;\n"
                + "        } catch (Exception $ex) {\n"
                + "            echo $ex->getMessage();\n"
                + "        } \n\n"
                + "         return $resultado;\n\n"
                + "    }\n\n", primaMaiuscula(nomeTabela),
                nomeTabela,
                pk, primaMaiuscula(pk)));
        return sb.toString();
    }

    private String delete(String pk) {
        StringBuilder sb = new StringBuilder();

        sb.append(String.format(""
                + "    public function deletar(%s $instancia) {\n\n"
                + "        $resultado = false;\n"
                + "        try {\n"
                + "            $id = $instancia->get%s();\n\n"
                + "            $sql = \"delete from %s where %s = \" . $id;\n\n"
                + "            Conexao::querySql($sql);\n\n"
                + "            $resultado = true;\n"
                + "        } catch (Exception $ex) {\n"
                + "            echo $ex->getMessage();\n"
                + "        }\n"
                + "        return $resultado;\n"
                + "    }\n\n", primaMaiuscula(nomeTabela),
                primaMaiuscula(pk),
                pk, nomeTabela, pk));

        return sb.toString();
    }

    private String select(String pk) {
        StringBuilder sb = new StringBuilder();

        sb.append(String.format(""
                + "    public function localizar($id) {\n\n"
                + "        $lista;\n"
                + "        try {\n\n"
                + "            $sql = \"select * from %s\";\n\n"
                + "            if ($id != null) {\n"
                + "                $sql = $sql . \" where %s = \" . $id;\n"
                + "            }\n\n"
                + "            $lista = $this->executaConsulta($sql);\n"
                + "        } catch (Exception $ex) {\n"
                + "            echo $ex->getMessage();\n"
                + "        }\n\n"
                + "        return $lista;\n"
                + "    }\n\n"
                + "    public function localizarTodos() {\n\n"
                + "        $lista;\n"
                + "        $id = null;\n"
                + "        $lista = $this->localizar($id);\n\n"
                + "        return $lista;\n"
                + "    }\n\n", nomeTabela, pk));



        return sb.toString();
    }

    private String executaConsulta(StringBuilder valores) {
        StringBuilder sb = new StringBuilder();

        sb.append(String.format(""
                + "    private function executaConsulta($sql) {\n\n"
                + "        $result = Conexao::querySql($sql);\n"
                + "        $i = 0;\n\n"
                + "        while ($row = pg_fetch_array($result)) {\n\n"
                + "            $%s = new %s();\n\n"
                + valores.toString()
                + "            $lista[$i] = $%s;\n"
                + "            $i++;\n"
                + "        }\n\n"
                + "        return $lista;\n\n"
                + "    }\n\n",
                nomeTabela,
                primaMaiuscula(nomeTabela),
                nomeTabela));

        return sb.toString();
    }

    private String gerarSingletonConexao() {

        StringBuilder sb = new StringBuilder();
        sb.append(String.format("<?\n"
                + "class Conexao {\n"
                + "    public static $instance;\n"
                + "    private function __construct() {"
                + "    }\n\n"
                + "    public static function pg_opencon($conexao) {\n"
                + "        if (!isset(self::$instance)) {\n"
                + "            self::$instance = pg_connect($conexao);\n"
                + "        }\n\n"
                + "        return self::$instance;\n"
                + "    }\n\n"
                + "    public static function pg_closecon() {\n"
                + "        if (isset(self::$instance)) {\n"
                + "            pg_close(self::$instance);\n"
                + "            self::$instance = null;\n"
                + "        }\n"
                + "    }\n"
                + "    public static function querySql($string) {\n"
                + "        //include('paramIni.php');\n"
                + "        if($conexao == null || $conexao == ''){\n"
                + "           $conexao = 'host=%s port=%s dbname=%s user=%s password=%s';\n"
                + "        }\n\n"
                + "        $query = pg_query(self::pg_opencon($conexao), $string);\n"
                + "        self::pg_closecon();\n"
                + "        return $query;\n\n"
                + "    }\n"
                + "}\n\n"
                + "?>", host, porta, db, login, senha));




        return sb.toString();
    }

    private String primaMaiuscula(String palavra) {

        String retorno = "";

        String[] partes = palavra.split("_");

        for (String plv : partes) {
            retorno += plv.substring(0, 1).toUpperCase() + plv.substring(1);
        }

        String palavras = palavra.substring(0, 1).toUpperCase() + palavra.substring(1);

        return retorno;
    }

    public String getCodigoDAO() {
        return codigoDAO;
    }

    public String getCodigoEntidade() {
        return codigoEntidade;
    }

    public void setListaAtributos(ArrayList listaAtributos) {
        this.listaAtributos = listaAtributos;
    }

    public String getMsgErro() {
        return msgErro;
    }

    public void setCampoPk(String campoPk) {
        for (int i = 0; i < listaAtributos.size(); i++) {
            ArrayList listaTmp = (ArrayList) listaAtributos.get(i);
            String nomeCampo = listaTmp.get(1).toString();
            String campoTipo = listaTmp.get(2).toString();

            if (nomeCampo.equalsIgnoreCase(campoPk)) {
                listaAtributos.remove(listaAtributos.get(i));

                ArrayList campos = new ArrayList();

                campos.add("PK");
                campos.add(nomeCampo);
                campos.add(campoTipo);
                campos.add(listaTmp.get(3).toString());

                listaAtributos.add(campos);
            }
        }
    }
}
